package com.mjf.stack;

import java.util.Scanner;

/**
 * 实现简易计算器(使用两个栈分别存放数字与运算符)
 * <p>
 * 实现思路：
 * 遍历表达式
 *   - 当前字符为操作符时
 *     + 以下情况操作符直接入栈
 *       1.操作符栈为空
 *       2.当前操作符优先级大于操作符栈顶操作符优先级
 *     + 当前操作符优先级小于等于操作符栈顶操作符优先级时
 *       1.从数字栈中取出两个数字，操作符栈取出一个操作符
 *       2.执行运算，将结果存入数字栈
 *       3.当前操作符入栈
 *   - 当前字符为数字时，一直遍历，直到遍历结束或者遍历到操作符。将所有数字拼接后入数字栈
 *   - 当表达式遍历结束以后，将数字栈与操作符栈中的数据依次取出计算，直到数字栈中只剩一个元素即为最后结果
 */
public class Calculator {
    public static void main(String[] args) {

        // 数字栈
        ArrayStack numStack = new ArrayStack(10);
        // 运算符栈
        ArrayStack operatorStack = new ArrayStack(10);

        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入表达式：");
        String expression = scanner.next(); // 接收用户输入表达式

        // 遍历用户输入表达式
        for (int i = 0; i < expression.length(); i++) {
            char pointer = expression.charAt(i);
            if (isOperator(pointer)) { // 判断是否为操作符
                // 以下情况操作符直接入栈
                // 1.操作符栈为空
                // 2.当前操作符优先级大于操作符栈顶操作符优先级
                if (operatorStack.isEmpty() || priority(pointer) > priority(operatorStack.peek())) {
                    operatorStack.push(pointer);
                } else {
                    // 当前操作符优先级小于等于操作符栈顶操作符优先级时
                    // 1.从数字栈中取出两个数字，操作符栈取出一个操作符
                    // 2.执行运算，将结果存入数字栈
                    // 3.当前操作符入栈
                    int num1 = numStack.pop();
                    int num2 = numStack.pop();
                    int operator = operatorStack.pop();
                    numStack.push(cal(num1, num2, operator));
                    operatorStack.push(pointer);
                }
            } else {
                StringBuilder number = new StringBuilder("" + pointer);
                // 处理多位数字
                while ((i + 1) < expression.length() && !isOperator(expression.charAt(i + 1))) {
                    number.append(expression.charAt(i + 1));
                    i++;
                }
                numStack.push(Integer.parseInt(number.toString()));
            }
        }

        // 当表达式遍历结束以后，将数字栈与操作符栈中的数据依次取出计算，直到数字栈中只剩一个元素即为最后结果
        int num1;
        while (true) {
            num1 = numStack.pop();
            if (numStack.isEmpty()) {
                break;
            }
            int num2 = numStack.pop();
            int operator = operatorStack.pop();
            numStack.push(cal(num1, num2, operator));
        }

        System.out.printf("%s = %d", expression, num1);

    }

    /**
     * 返回运算符优先级
     *
     * @return 优先级
     */
    public static int priority(int operator) {
        if (operator == '*' || operator == '/') {
            return 1;
        } else if (operator == '+' || operator == '-') {
            return 0;
        } else {
            return -1;  // 假定表达式只有 + - * /
        }
    }

    /**
     * 判断是否为操作符
     */
    public static boolean isOperator(char operator) {
        return operator == '+' || operator == '-' || operator == '*' || operator == '/';
    }

    /**
     * 计算方法
     */
    public static int cal(int num1, int num2, int operator) {
        int res = 0;
        switch (operator) {
            case '+':
                res = num1 + num2;
                break;
            case '-':
                res = num2 - num1;  // 注意顺序
                break;
            case '*':
                res = num1 * num2;
                break;
            case '/':
                res = num2 / num1;  // 注意顺序
                break;
            default:
                break;
        }
        return res;
    }
}
